﻿//Mirco Töpfer

#region Usings

using System;
using System.Collections.Generic;
using pheidippides.configuration.Interfaces;
using System.Reflection;
using System.IO;
using pheidippides.logging.Classes;
using pheidippides.exceptionmanager.Classes;

#endregion

namespace pheidippides.configuration.Classes
{
    public class ConfigManager : IConfigurationManager
    {
        #region Singleton Kram

        private static ConfigManager staticConfigManager;

        public static ConfigManager GetInstance()
        {
            if (staticConfigManager == null)
                staticConfigManager = new ConfigManager();
            return staticConfigManager;
        }

        #endregion

        #region Private Members

        private readonly Dictionary<ConfigEntryName, String> persistentConfigEntrys;
        private readonly Dictionary<ConfigEntryName, String> configFileConfigEntrys;

        private readonly String ConfigFilePath =
            Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
                         Path.Combine("Config", "Config.cfg"));

        #endregion

        #region Constructor

        public ConfigManager()
        {
            persistentConfigEntrys = GeneratePersistentEntrys();
            configFileConfigEntrys = ReadConfigFile();
        }

        #endregion

        #region Public Methods

        public String GetConfigEnry(ConfigEntryName Name)
        {
            Logger.GetInstance().LogMessage("Anfragen des Configentrys " + Name, LogLevel.Debug);

            if (configFileConfigEntrys.ContainsKey(Name))
            {
                String ValuePers = configFileConfigEntrys[Name];
                Logger.GetInstance().LogMessage("Configentry aus ConfigFile" + Name + " = " + ValuePers, LogLevel.Debug);
                return ValuePers;
            }
            else if (persistentConfigEntrys.ContainsKey(Name))
            {
                String ValuePers = persistentConfigEntrys[Name];
                Logger.GetInstance().LogMessage("Persistenter Configentry" + Name + " = " + ValuePers, LogLevel.Debug);
                return ValuePers;
            }
            else
            {
                Logger.GetInstance().LogMessage("Der Configeintrag " + Name + " konnte nicht gefunden werden!",
                                                LogLevel.Warning);
                return null;
            }
        }

        public void SetConfigEntry(ConfigEntryName Name, String Value)
        {
            Logger.GetInstance().LogMessage("Speichern von ConfigValue " + Name + " mit Wert " + Value,
                                            LogLevel.Info);
            try
            {
                if (!configFileConfigEntrys.ContainsKey(Name))
                    configFileConfigEntrys.Add(Name, Value);
                else
                    configFileConfigEntrys[Name] = Value;

                WriteConfigFile(configFileConfigEntrys);
            }
            catch (Exception ex)
            {
                Logger.GetInstance().LogException("Fehler beim Speichern des Configfiles unter " + ConfigFilePath,
                                                  ex, LogLevel.Exception);
                ExceptionManager.GetInstance().RegisterException(
                    "Fehler beim Speichern des Configfiles unter " + ConfigFilePath, ex);
            }
        }

        /// <summary>
        /// Gibt die Guid der aktuell geöffneten Veranstaltung zurück.
        /// </summary>
        /// <returns></returns>
        public Guid GetVeranstaltungsId()
        {
            return new Guid(GetConfigEnry(ConfigEntryName.VeranstaltungsId));
        }

        /// <summary>
        /// Setzt die ID der aktuellen Veranstaltung die bearbeitet/geöffnet ist.
        /// </summary>
        /// <param name="guid">Veranstaltungs-GUID.</param>
        public void SetVeranstaltungsId(Guid guid)
        {
            SetConfigEntry(ConfigEntryName.VeranstaltungsId, guid.ToString());
        }

        /// <summary>
        /// Gets the database path.
        /// </summary>
        /// <returns></returns>
        public String GetDatabasePath()
        {
            return GetConfigEnry(ConfigEntryName.DatabasePath);
        }
        #endregion

        #region Private Methods

        private Dictionary<ConfigEntryName, String> ReadConfigFile()
        {
            Logger.GetInstance().LogMessage("Lesen der Configdatei " + ConfigFilePath, LogLevel.Debug);

            Dictionary<ConfigEntryName, String> ConfigEntrys = new Dictionary<ConfigEntryName, String>();

            if (!File.Exists(ConfigFilePath))
            {
                Logger.GetInstance().LogMessage(
                    "Configdatei " + ConfigFilePath + "wurde nicht gefunden. Datei wird erstellt", LogLevel.Warning);

                Directory.CreateDirectory(Path.GetDirectoryName(ConfigFilePath));

                File.CreateText(ConfigFilePath);
                return ConfigEntrys;
            }

            FileStream FStream = null;
            StreamReader SReader = null;

            try
            {
                FStream = File.OpenRead(ConfigFilePath);
                SReader = new StreamReader(FStream);

                while (!SReader.EndOfStream)
                {
                    String Line = SReader.ReadLine();
                    try
                    {
                        if (!Line.Contains("->"))
                            continue;

                        String[] Splitted = Line.Split(new[] {"->"}, StringSplitOptions.RemoveEmptyEntries);

                        if (new List<String>(Splitted).Count > 2)
                            throw new Exception("Die Zeile enthält zu viele Speratoren ->");

                        ConfigEntryName Name = GetConfigEntryName(Splitted[0]);

                        ConfigEntrys.Add(Name, Splitted[1]);
                    }
                    catch (Exception ex)
                    {
                        Logger.GetInstance().LogException("Fehler beim Erzeugen des ConfigEntrys aus Eintrag " + Line,
                                                          ex, LogLevel.Exception);
                    }
                }

                return ConfigEntrys;
            }
            catch (Exception ex)
            {
                Logger.GetInstance().LogException("Fehler beim lesen der Konfigurationsdatei", ex, LogLevel.Exception);
                return ConfigEntrys;
            }
            finally
            {
                if (SReader != null) SReader.Close();
                if (FStream != null) FStream.Close();
            }
        }

        private void WriteConfigFile(Dictionary<ConfigEntryName, String> Entrys)
        {
            Logger.GetInstance().LogMessage("Schreibe neue Config Datei " + ConfigFilePath, LogLevel.Debug);

            FileStream Fstream = null;
            StreamWriter SWriter = null;

            try
            {
                Fstream = File.Create(ConfigFilePath);
                SWriter = new StreamWriter(Fstream);

                foreach (KeyValuePair<ConfigEntryName, String> item in Entrys)
                {
                    SWriter.WriteLine(item.Key + "->" + item.Value);
                }
            }
            catch (Exception ex)
            {
                Logger.GetInstance().LogException("Fehler beim schreiben des Configfiles", ex, LogLevel.Exception);
            }
            finally
            {
                if (SWriter != null) SWriter.Close();
                if (Fstream != null) Fstream.Close();
            }
        }

        private Dictionary<ConfigEntryName, String> GeneratePersistentEntrys()
        {
            Dictionary<ConfigEntryName, String> persistentConfigEntrys = new Dictionary<ConfigEntryName, String>();

            persistentConfigEntrys.Add(ConfigEntryName.PheidippidesInfoWebsiteURL, @"http://pheidippides.codeplex.com/");
            persistentConfigEntrys.Add(ConfigEntryName.PheidippidesBugFeatureWebsiteURL,
                                       @"http://pheidippides.codeplex.com/workitem/list/basic");
            persistentConfigEntrys.Add(ConfigEntryName.PheidippidesLicenseWebsiteURL,
                                       @"http://pheidippides.codeplex.com/license");

            persistentConfigEntrys.Add(ConfigEntryName.VeranstaltungsId, Guid.Empty.ToString());

            String DatabasePath =
                Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), "Database"),
                             "Database.mdb");
            persistentConfigEntrys.Add(ConfigEntryName.DatabasePath, DatabasePath);


            return persistentConfigEntrys;
        }

        private ConfigEntryName GetConfigEntryName(string StrgName)
        {
            foreach (ConfigEntryName Name in Enum.GetValues(typeof (ConfigEntryName)))
            {
                if (StrgName.Equals(Name.ToString()))
                    return Name;
            }

            throw new ApplicationException("Der Configname " + StrgName + " konnte nicht auf ein Enum gemappt werden!");
        }

        #endregion


    }
}